package schedule;

import java.util.ArrayList;

import plan.Belegung;
import plan.Plan;
import util.Interval;
import util.JSONParser;
import auftrag.Auftrag;
import auftrag.Operation;
import auftrag.Produkt;
import auftrag.Variante;

public class FindeNachbarnEins {

	public Plan findeNachbarnEins(Plan planInitial) {

		/*
		 * Lese die Ausgangsliste ein, mit der der erste Plan erstellt wurde
		 */
		int intAusgangswert = 0;
		ArrayList<Auftrag> arrHilfAusg = new ArrayList<Auftrag>();
		for (int intIndexA = 0; intIndexA < planInitial.getBelegungen().size(); intIndexA++) {
			boolean booIndexA = false;
			if (arrHilfAusg.isEmpty()) {
				arrHilfAusg.add(planInitial.getBelegungen().get(intIndexA)
						.getAuftrag());
			} else {
				for (int intIndexB = 0; intIndexB < arrHilfAusg.size()
						&& booIndexA == false; intIndexB++) {
					if (arrHilfAusg.get(intIndexB) == planInitial
							.getBelegungen().get(intIndexA).getAuftrag())
						booIndexA = true;
				}
				if (booIndexA == false)
					arrHilfAusg.add(planInitial.getBelegungen().get(intIndexA)
							.getAuftrag());
			}
		}

		/*
		 * Sortiere die Liste wieder nach EDF und der Priorität, so dass die
		 * Aufträge als erstes mit der höchsten Priorität bearbeitet werden und
		 * darin nocheinmal nach Deadlines sortiert werden
		 */
		ArrayList<Auftrag> arrAusgangsliste = new ArrayList<Auftrag>();
		for (int intIndexA = 0; intIndexA < arrHilfAusg.size(); intIndexA++) {
			if (arrAusgangsliste.isEmpty()) {
				arrAusgangsliste.add(arrHilfAusg.get(intIndexA));
			} else {
				for (int intIndexB = 0; intIndexB < arrAusgangsliste.size(); intIndexB++) {
					if (arrAusgangsliste.get(intIndexB).getPriority() < arrHilfAusg
							.get(intIndexA).getPriority()) {
						arrAusgangsliste.add(intIndexB,
								arrHilfAusg.get(intIndexA));
						intIndexB = arrAusgangsliste.size();
					} else if (arrAusgangsliste.get(intIndexB).getPriority() == arrHilfAusg
							.get(intIndexA).getPriority()
							&& arrAusgangsliste.get(intIndexB).getDeadline() > arrHilfAusg
									.get(intIndexA).getDeadline()) {
						arrAusgangsliste.add(intIndexB,
								arrHilfAusg.get(intIndexA));
						intIndexB = arrAusgangsliste.size();
					} else if ((intIndexB + 1) >= arrAusgangsliste.size()) {
						arrAusgangsliste.add(arrHilfAusg.get(intIndexA));
						intIndexB = arrAusgangsliste.size();
					}
				}
			}
		}

		/*
		 * Berechnen des Vergleichwertes des ursprünglichen Plans
		 */
		for (Auftrag a : arrAusgangsliste) {
			int delay = Math.max(a.getEndDate() - a.getDeadline(), 0);
			intAusgangswert += delay * a.getPriority();
		}

		/*
		 * Neue Auftragsliste erzeugen, bei denen die Belegung auf Null gesetzt
		 * ist um zum Vergleich genutzt zu werden
		 */
		JSONParser parser = new JSONParser("beispieldata_1.json");
		ArrayList<Auftrag> newAuftragsListe = new ArrayList<Auftrag>();
		newAuftragsListe = parser.getOrders();

		/*
		 * Sortiere die Liste auch wieder nach dem gleichen Schema wie die alte
		 * Liste
		 */
		ArrayList<Auftrag> arrNewAufLi = new ArrayList<Auftrag>();
		for (int intIndexA = 0; intIndexA < newAuftragsListe.size(); intIndexA++) {
			if (arrNewAufLi.isEmpty()) {
				arrNewAufLi.add(newAuftragsListe.get(intIndexA));
			} else {
				for (int intIndexB = 0; intIndexB < arrNewAufLi.size(); intIndexB++) {
					if (arrNewAufLi.get(intIndexB).getPriority() < newAuftragsListe
							.get(intIndexA).getPriority()) {
						arrNewAufLi.add(intIndexB,
								newAuftragsListe.get(intIndexA));
						intIndexB = arrNewAufLi.size();
					} else if (arrNewAufLi.get(intIndexB).getPriority() == newAuftragsListe
							.get(intIndexA).getPriority()
							&& arrNewAufLi.get(intIndexB).getDeadline() > newAuftragsListe
									.get(intIndexA).getDeadline()) {
						arrNewAufLi.add(intIndexB,
								newAuftragsListe.get(intIndexA));
						intIndexB = arrNewAufLi.size();
					} else if ((intIndexB + 1) >= arrNewAufLi.size()) {
						arrNewAufLi.add(newAuftragsListe.get(intIndexA));
						intIndexB = arrNewAufLi.size();
					}
				}
			}
		}

		/*
		 * Erstelle eine Liste, wo durchgegangen wird ob die Deadline von
		 * Auftrag x eingehalten wird. Wenn das nicht so ist, dann schaue bei
		 * Auftrag x-1 ob da die Deadline eingehalten wird und tausche diese
		 * dann
		 */
		newAuftragsListe = new ArrayList<Auftrag>();
		newAuftragsListe.add(arrNewAufLi.get(0));

		for (int intIndexA = 1; intIndexA < arrNewAufLi.size(); intIndexA++) {
			if (arrAusgangsliste.get(intIndexA).getDeadline() < arrAusgangsliste
					.get(intIndexA).getEndDate()
					&& arrAusgangsliste.get(intIndexA - 1).getDeadline() > arrAusgangsliste
							.get(intIndexA - 1).getEndDate()) {
				newAuftragsListe.add((intIndexA - 1),
						arrNewAufLi.get(intIndexA));
			} else {
				newAuftragsListe.add(arrNewAufLi.get(intIndexA));
			}
		}

		int intIndexC;
		Plan p = new Plan();
		for (int intIndexA = 0; intIndexA < newAuftragsListe.size(); intIndexA++) {
			Auftrag aufAuftragA = newAuftragsListe.get(intIndexA);
			intIndexC = 0;
			// Plane die komplette Menge an Produkten ein
			for (int intIndexB = 0; intIndexB < aufAuftragA
					.getAuftragProdukteSize(); intIndexB++) {
				Produkt proProduktA = aufAuftragA.getAuftragProdukte().get(
						intIndexB);
				if (proProduktA.getChosenVariante() == null)
					proProduktA.chooseVariant(intIndexC, false);
				Variante varVarianteA = proProduktA.getChosenVariante();
				intIndexC++;
				if (intIndexC >= proProduktA.getProduktVariante().size())
					intIndexC = 0;
				// Plane erst eine komplette Variante ein
				for (int intIndexD = 1; intIndexD <= varVarianteA
						.getOperationSize(); intIndexD++) {
					Operation opeOperationA = varVarianteA
							.getOperation(intIndexD);
					Interval intIntervalA;
					if (opeOperationA.getPreviousOperation() == null)
						intIntervalA = opeOperationA.getRessource()
								.getFirstUnoccupiedInterval(0,
										opeOperationA.getDuration());
					else {
						intIntervalA = opeOperationA.getRessource()
								.getFirstUnoccupiedInterval(
										opeOperationA.getPreviousOperation()
												.getInterval().getEnd(),
										opeOperationA.getDuration());
					}
					Belegung belBelegungA = new Belegung(opeOperationA,
							intIntervalA);
					p.addBelegung(belBelegungA);
				}
			}
		}

		int intVergleichswert = 0;
		for (Auftrag a : newAuftragsListe) {
			int delay = Math.max(a.getEndDate() - a.getDeadline(), 0);
			intVergleichswert += delay * a.getPriority();
		}

		/*
		 * Gebe den neuen Plan zurück, wenn dieser besser ist als der alte Plan
		 */
		if (intVergleichswert < intAusgangswert) {
			return p;
		}

		/*
		 * Wenn der neue Plan nicht besser ist, dann gebe null zurück
		 */
		return null;
	}
}
